from fastapi import APIRouter, Depends, HTTPException
from factorapp.models import AsyncSessionFactory
from sqlalchemy.ext.asyncio import AsyncSession
from factorapp.schemas import FactorCreateReqModel, FactorUpdateReqModel
from factorapp.models import Factor
from common.log import LOG, LogLevel
from sqlalchemy import delete, select, update


router = APIRouter(prefix="/factor", tags=["因子模块"])


# 函数依赖（获取异步数据库会话）
async def get_asyncsession():
    session = AsyncSessionFactory()
    try:
        yield session
    finally:
        await session.close()


@router.post('/create', description="创建因子")
async def create_factor(
    factor_body: FactorCreateReqModel, 
    session: AsyncSession=Depends(get_asyncsession)
):
    try:
        async with session.begin():
            factory = Factor(name=factor_body.name, content=factor_body.content, info=factor_body.info)
            session.add(factory)
            return {"message": "因子创建成功！"}
    except Exception as e:
        LOG(LogLevel.ERROR) << f"因子创建失败: {str(e)}" << "\n"
        raise HTTPException(status_code=400, detail="因子创建失败！")


@router.delete('/delete/{id}', description="删除指定因子")
async def delete_factor(id: int, session: AsyncSession=Depends(get_asyncsession)):
    try:
        async with session.begin():
            sql = delete(Factor).where(Factor.id==id)
            await session.execute(sql)
            return {"message": "删除成功！"}
    except Exception as e:
        LOG(LogLevel.ERROR) << f"删除id为{id}的因子失败：{str(e)}" << "\n"
        raise HTTPException(status_code=400, detail='删除失败！')


@router.get('/all', description="获取所有因子")
async def all_factors(session: AsyncSession=Depends(get_asyncsession)):
    try:
        async with session.begin():
            stmt = select(Factor)  
            result = await session.execute(stmt)
            factors = result.scalars().all()
            return {
                "message": "获取因子列表成功",
                "data": [factor.__dict__ for factor in factors]
            }
    except Exception as e:
        LOG(LogLevel.ERROR) << f"获取所有因子失败：{str(e)}" << "\n"
        raise HTTPException(status_code=400, detail="获取所有因子失败！")


@router.get('/one/{id}', description="查询某一个因子")
async def one_factor(id: int, session: AsyncSession=Depends(get_asyncsession)):
    try:
        async with session.begin():
            stmt = select(Factor).where(Factor.id==id)
            result = await session.execute(stmt)
            factor = result.scalars().first()
            if not factor: # 如果因子不存在，则抛出异常
                raise HTTPException(status_code=400, detail=f"ID为 {id} 的因子不存在！")
            return {
                "message": "获取因子成功",
                "data": factor.__dict__
            }
    except HTTPException:
        raise
    except Exception as e:
        LOG(LogLevel.ERROR) << f"获取因子失败：{str(e)}" << "\n"
        raise HTTPException(status_code=400, detail="获取因子失败!")


@router.put('/update/{id}', description="修改因子")
async def update_factor(
    id: int, 
    update_data: FactorUpdateReqModel,
    session: AsyncSession=Depends(get_asyncsession),
):
    try:
        async with session.begin():
            # 1. 查询
            stmt = select(Factor).where(Factor.id==id)
            result = await session.execute(stmt)
            factor = result.scalars().first()
            if not factor:
                raise HTTPException(status_code=400, detail=f"ID为 {id} 的因子不存在！")
            # 2. 构建更新字典（排除未提供的字段）
            update_dict = update_data.model_dump(exclude_unset=True)
            # 3. 执行更新
            await session.execute(update(Factor).where(Factor.id==id).values(**update_dict))
            # 4. 重新查询获取更新后的数据
            result = await session.execute(select(Factor).where(Factor.id==id))
            updated_factor = result.scalars().first()
            # 5. 返回更新后的数据
            return {
                "message": "因子更新成功",
                "data": updated_factor.__dict__
            }
    except HTTPException:
        raise
    except Exception as e:
        LOG(LogLevel.ERROR) << f"更新因子失败: {str(e)}" << "\n"
        raise HTTPException(status_code=400, detail="更新因子失败!")